package a33

/*
 * by marius elkan
 */


object Ruby2 {

  def main(args: Array[String]) {
    val rs = RString("hello there")

    println(rs(1))
    println(rs(1, 3))
    println(rs(1 to 3))
    println(rs(-3, 2))
    println(rs(-4 to -2))
    println(rs(-2 to -4))
    println(rs("th[aeiou]".r))

    println(rs("lo"))
    println(rs("bye"))
  }

  object RString {
    def apply(s: String) = new RString(s)
  }

  object Rnil extends RString("") {
    override def apply(p: String) = Rnil
    override def apply(p: scala.util.matching.Regex) = Rnil
    override def toString() = "Rnil"
  }

  class RString(val s: String) {
    val size = s.size
    override def toString() = s

    def realIndex(i: Int) = {
      i match {
        case i if (i < -size) || (i >= size) => -1
        case i if (i < 0) => size + i
        case i => i
      }
    }

    def apply(i: Int) = if (realIndex(i) != -1) s(i).toByte else Rnil

    def apply(r: Range): RString = if (r.isEmpty) Rnil else apply(r.head, r.length)

    def apply(start: Int, len: Int) = {
      realIndex(start) match {
        case realStart if ((realStart == -1) || (len < 0)) => Rnil
        case realStart => RString(s.substring(realStart, size.min(realStart + len)))
      }
    }

    def apply(p: String) = if (s.contains(p)) RString(p) else Rnil

    def apply(p: scala.util.matching.Regex) = {
      p.findFirstIn(s) match {
        case Some(x) => RString(x)
        case None => Rnil
      }
    }

    //def scan(search: String): List[_] = scan(search.r)
    def scan(search: String) = {
      def inner(s: String, search: String, res: List[String] = List()): List[String] = {
        s match {
          case s if (s.isEmpty) => res
          case s if (s.startsWith(search)) => inner(s.stripPrefix(search), search, search :: res)
          case s => inner(s.tail, search, res)
        }
      }
      inner(s, search)
    }

    def scan(p: scala.util.matching.Regex) = {
      p.findAllIn(s) match {
        case stringIt if (stringIt.groupCount == 0) => stringIt.toList
        case stringIt => (for (m <- stringIt.matchData) yield m.subgroups).toList
      }
    }

  } //RString
}//Ruby